              package com.java.diagnostics.visualizer.impl.data;
              
              import com.java.diagnostics.visualizer.data.AggregateData;
              import com.java.diagnostics.visualizer.data.Aggregated;
              import com.java.diagnostics.visualizer.data.Data;
              import com.java.diagnostics.visualizer.data.StructuredData;
              import com.java.diagnostics.visualizer.data.TupleData;
              import com.java.diagnostics.visualizer.data.UnstructuredData;
              import com.java.diagnostics.visualizer.data.ids.ID;
              import com.java.diagnostics.visualizer.impl.factory.LogFactory;
              import java.util.Collection;
              import java.util.HashMap;
              import java.util.Iterator;
              import java.util.Map;
              import java.util.Set;
              import java.util.TreeMap;
              import java.util.logging.Logger;
              
              public abstract class AggregatedImpl extends AggregateDataImpl
                implements Aggregated
              {
                private static final Logger TRACE = LogFactory.getTrace(AggregatedImpl.class);
              
                private AggregateData representativeData = null;
              
                private final String className = getClass().getName();
              
                public AggregatedImpl(String label) {
                  super(label);
                }
              
                public AggregateData getRepresentativeData()
                {
                  TRACE.entering(this.className, "getRepresentativeData");
                  updateRepresentativeData();
                  TRACE.exiting(this.className, "getRepresentativeData");
              
                  return this.representativeData;
                }
              
                public abstract AggregateData[] getLowerDownHierarchyData();
              
                private void updateRepresentativeData()
                {
                  AggregateData localRepresentativeData = createLocalRepresentativeData();
              
                  AggregateData[] lowerDowns = getLowerDownHierarchyData();
              
                  if (lowerDowns != null) {
                    AggregateData[] representativeVariants = new AggregateData[lowerDowns.length];
                    for (int m = 0; m < lowerDowns.length; m++)
                    {
                      AggregatedImpl lowerDown = (AggregatedImpl)lowerDowns[m];
              
                      representativeVariants[m] = lowerDown.getRepresentativeData();
                    }
              
                    this.representativeData = 
                      produceRepresentativeData(localRepresentativeData, representativeVariants);
                  }
                  else
                  {
                    this.representativeData = localRepresentativeData;
                  }
              
                  this.dataIsDirty = false;
                }
              
                private AggregateData createLocalRepresentativeData()
                {
                  AggregateData localRepresentativeData = new AggregateDataImpl();
                  addStructuredDataToRepresentativeData(localRepresentativeData);
                  addUnstructuredDataToRepresentativeData(localRepresentativeData);
                  addTupleDataToRepresentativeData(localRepresentativeData);
                  return localRepresentativeData;
                }
              
                private void addTupleDataToRepresentativeData(AggregateData localRepresentativeData)
                {
                  Map tuples = new TreeMap();
              
                  TupleData[] tupleData = getTupleData();
                  for (int i = 0; i < tupleData.length; i++) {
                    tuples.put(tupleData[i].getID(), tupleData[i]);
                  }
              
                  Iterator it = tuples.values().iterator();
                  while (it.hasNext()) {
                    TupleData data = (TupleData)it.next();
                    RepresentativeTupleDataImpl rep = new RepresentativeTupleDataImpl(
                      (TupleDataImpl)data);
                    localRepresentativeData.add(rep);
                  }
                }
              
                private void addStructuredDataToRepresentativeData(AggregateData localRepresentativeData)
                {
                  Map structuredDatas = new TreeMap();
              
                  StructuredData[] structuredData = getStructuredData();
                  for (int i = 0; i < structuredData.length; i++) {
                    structuredDatas.put(structuredData[i].getID(), structuredData[i]);
                  }
              
                  Iterator it = structuredDatas.values().iterator();
                  while (it.hasNext()) {
                    StructuredData data = (StructuredData)it.next();
              
                    localRepresentativeData.add(new RepresentativeStructuredDataImpl(
                      data.getLabel(), data.getDisplayName(), data.getCategory(), data.getContents()));
                  }
                }
              
                private void addUnstructuredDataToRepresentativeData(AggregateData localRepresentativeData)
                {
                  Map unstructuredDatas = new TreeMap();
              
                  UnstructuredData[] unstructuredData = getUnstructuredData();
                  for (int i = 0; i < unstructuredData.length; i++) {
                    unstructuredDatas.put(unstructuredData[i].getLabel(), 
                      unstructuredData[i]);
                  }
              
                  Iterator it = unstructuredDatas.values().iterator();
                  while (it.hasNext()) {
                    UnstructuredData data = (UnstructuredData)it.next();
                    localRepresentativeData.add(new RepresentativeUnstructuredDataImpl(
                      data.getLabel(), data.getDisplayName(), data.getCategory(), data.getValue()));
                  }
                }
              
                private AggregateData produceRepresentativeData(AggregateData existingRepresentation, AggregateData[] aggregateData)
                {
                  AggregateDataImpl representation = new AggregateDataImpl();
                  UnstructuredData[] existingUnstructuredData = existingRepresentation
                    .getUnstructuredData();
              
                  for (int i = 0; i < existingUnstructuredData.length; i++)
                  {
                    if ((existingUnstructuredData[i].getValue().length() > 0) || 
                      (representation.getData(
                      existingUnstructuredData[i].getID()) == null)) {
                      representation.add(existingUnstructuredData[i]);
                    }
                  }
              
                  StructuredData[] existingStructuredData = existingRepresentation
                    .getStructuredData();
              
                  for (int i = 0; i < existingStructuredData.length; i++)
                  {
                    StructuredData thisStructuredData = existingStructuredData[i];
                    if ((thisStructuredData.getColumnNames().size() > 0) || 
                      (representation.getData(thisStructuredData.getID()) == null)) {
                      representation.add(thisStructuredData);
                    }
                  }
              
                  TupleData[] existingTupleData = existingRepresentation.getTupleData();
              
                  Map tuples = new TreeMap();
                  Map structs = new TreeMap();
                  Map unstructs = new TreeMap();
              
                  addToMap(existingTupleData, tuples);
                  addToMap(existingStructuredData, structs);
                  addToMap(existingUnstructuredData, unstructs);
              
                  for (int i = 0; i < aggregateData.length; i++) {
                    if (aggregateData[i] != null) {
                      mergeUnstructuredData(unstructs, aggregateData[i]);
                      mergeStructuredData(structs, aggregateData[i]);
                      mergeTupleData(tuples, aggregateData[i]);
                    }
              
                  }
              
                  Iterator it = unstructs.values().iterator();
                  while (it.hasNext()) {
                    UnstructuredData data = (UnstructuredData)it.next();
                    representation.add(data);
                  }
              
                  it = structs.values().iterator();
                  while (it.hasNext()) {
                    StructuredData data = (StructuredData)it.next();
                    representation.add(data);
                  }
              
                  it = tuples.values().iterator();
                  while (it.hasNext()) {
                    TupleData data = (TupleData)it.next();
                    representation.add(data);
                  }
              
                  return representation;
                }
              
                private void addToMap(Data[] existingData, Map map) {
                  for (int i = 0; i < existingData.length; i++) {
                    Data data = existingData[i];
              
                    map.put(data.getID(), data);
                  }
                }
              
                private Map mergeTupleData(Map tuples, AggregateData aggregateData)
                {
                  TupleData[] allTupleData = aggregateData.getTupleData();
              
                  int count = allTupleData.length;
              
                  for (int j = 0; j < count; j++) {
                    TupleDataImpl tupleData = (TupleDataImpl)allTupleData[j];
              
                    ID id = tupleData.getID();
              
                    RepresentativeTupleDataImpl data = 
                      (RepresentativeTupleDataImpl)tuples
                      .get(id);
                    if ((data == null) || (data.isEmpty()))
                    {
                      data = new RepresentativeTupleDataImpl(tupleData);
              
                      tuples.put(id, data);
                    }
                    else
                    {
                      data.mergeInData(tupleData);
                    }
                  }
              
                  return tuples;
                }
              
                private Map mergeStructuredData(Map structs, AggregateData aggregateData)
                {
                  StructuredData[] allStructuredData = aggregateData.getStructuredData();
              
                  int count = allStructuredData.length;
              
                  for (int j = 0; j < count; j++) {
                    StructuredData structuredData = allStructuredData[j];
              
                    ID id = structuredData.getID();
              
                    RepresentativeStructuredDataImpl data = 
                      (RepresentativeStructuredDataImpl)structs
                      .get(id);
                    if ((data == null) || (data.isEmpty()))
                    {
                      String label = structuredData.getLabel();
                      String displayName = structuredData.getDisplayName();
                      String category = structuredData.getCategory();
              
                      Map originalMap = structuredData.getContents();
                      Map newMap = new HashMap();
                      newMap.putAll(originalMap);
                      data = new RepresentativeStructuredDataImpl(label, displayName, category, 
                        newMap);
              
                      structs.put(id, data);
                    } else {
                      data.mergeInData(structuredData);
                    }
                  }
              
                  return structs;
                }
              
                private Map mergeUnstructuredData(Map unstructs, AggregateData aggregateData)
                {
                  UnstructuredData[] allUnstructuredData = aggregateData
                    .getUnstructuredData();
              
                  int count = allUnstructuredData.length;
              
                  for (int j = 0; j < count; j++) {
                    UnstructuredData unstructuredData = allUnstructuredData[j];
              
                    ID id = unstructuredData.getID();
                    String label = unstructuredData.getLabel();
                    String displayName = unstructuredData.getDisplayName();
              
                    RepresentativeUnstructuredDataImpl data = 
                      (RepresentativeUnstructuredDataImpl)unstructs
                      .get(id);
                    if ((data == null) || (data.isEmpty()))
                    {
                      String category = unstructuredData.getCategory();
                      String value = unstructuredData.getValue();
                      data = new RepresentativeUnstructuredDataImpl(label, displayName, category, 
                        value);
              
                      unstructs.put(id, data);
                    } else {
                      data.mergeInData(unstructuredData);
                    }
                  }
              
                  return unstructs;
                }
              
                public String getLabel() {
                  return this.label;
                }
              
                public void switchToPostprocessing() {
                  super.switchToPostprocessing();
                  AggregateData[] lowers = getLowerDownHierarchyData();
                  if (lowers != null)
                    for (int i = 0; i < lowers.length; i++)
                      ((AggregateDataImpl)lowers[i]).switchToPostprocessing();
                }
              
                public void clearPostprocessedLayer()
                {
                  super.clearPostprocessedLayer();
                  AggregateData[] lowers = getLowerDownHierarchyData();
                  if (lowers != null)
                    for (int i = 0; i < lowers.length; i++)
                      ((AggregateDataImpl)lowers[i]).clearPostprocessedLayer();
                }
              }

